<template>
  <div v-show="showBox" :class="mode === 'pop' ? 'mask' : ''">
    <div
      :class="mode === 'pop' ? 'verifybox' : ''"
      :style="{ maxWidth: parseInt(imgSize.width as any) + 30 + 'px' }"
    >
      <div v-if="mode === 'pop'" class="verifybox-top">
        请完成安全验证
        <span class="verifybox-close" @click="closeBox">
          <i class="iconfont icon-close" />
        </span>
      </div>
      <div class="verifybox-bottom" :style="{ padding: mode === 'pop' ? '15px' : '0' }">
        <component
          :is="componentType"
          v-if="componentType"
          ref="instanceRef"
          :captcha-type="captchaType"
          :type="verifyType"
          :figure="figure"
          :arith="arith"
          :mode="mode"
          :v-space="vSpace"
          :explain="explain"
          :img-size="imgSize"
          :block-size="blockSize"
          :bar-size="barSize"
          :default-img="defaultImg"
          @success="onSuccess"
          @error="onError"
        />
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { computed, onMounted, ref, watch, shallowRef, markRaw } from 'vue'
import VerifySlide from '@/components/common/verifyCode/VerifySlide.vue'
import VerifyPoints from '@/components/common/verifyCode/VerifyPoints.vue'
import { generateUuid } from '@/utils/AJCaptcha'

// Props
interface ImgSize {
  width: string
  height: string
}
interface BlockSize {
  width: string
  height: string
}
interface BarSize {
  width: string
  height: string
}

const props = withDefaults(
  defineProps<{
    locale?: string
    captchaType: string
    figure?: number
    arith?: number
    mode?: 'pop' | 'fixed'
    vSpace?: number
    explain?: string
    imgSize?: ImgSize
    blockSize?: BlockSize
    barSize?: BarSize
  }>(),
  {
    locale: navigator.language,
    mode: 'pop',
    vSpace: 5,
    explain: '向右滑动完成验证',
    imgSize: () => ({ width: '310px', height: '155px' }),
    blockSize: () => ({ width: '50px', height: '50px' }),
    barSize: () => ({ width: '310px', height: '40px' }),
  },
)

// State
const clickShow = ref(false)
const verifyType = ref<string | undefined>(undefined)
const componentType = shallowRef<any>(undefined)
const defaultImg = ref<string>(new URL('@/assets/star.jpg', import.meta.url).href)

const instanceRef = ref<any>()

const showBox = computed(() => (props.mode === 'pop' ? clickShow.value : true))

watch(
  () => props.captchaType,
  (captchaType) => {
    switch (String(captchaType)) {
      case 'blockPuzzle':
        verifyType.value = '2'
        componentType.value = markRaw(VerifySlide)
        break
      case 'clickWord':
        verifyType.value = undefined
        componentType.value = markRaw(VerifyPoints)
        break
      default:
        componentType.value = markRaw(VerifySlide)
        verifyType.value = '2'
    }
  },
  { immediate: true },
)

onMounted(() => {
  ensureUuid()
})

function ensureUuid() {
  const slider = 'slider-' + generateUuid()
  const point = 'point-' + generateUuid()
  if (!localStorage.getItem('slider')) {
    localStorage.setItem('slider', slider)
  }
  if (!localStorage.getItem('point')) {
    localStorage.setItem('point', point)
  }
}

function refresh() {
  instanceRef.value?.refresh?.()
}

function closeBox() {
  clickShow.value = false
  // 关闭时刷新，使下次打开为初始状态
  refresh()
}

function show() {
  if (props.mode === 'pop') {
    clickShow.value = true
  }
}

function onSuccess(payload: any) {
  // 验证成功：若为弹窗模式，自动关闭
  if (props.mode === 'pop') {
    closeBox()
  }
  // 透传给父层
  emit('success', payload)
}
function onError(e: any) {
  // 验证失败：保持弹窗开启，便于重试（子组件内部会自行 refresh）
  emit('error', e)
}

const emit = defineEmits<{
  (e: 'success', payload: any): void
  (e: 'error', payload: any): void
}>()

defineExpose({ show, refresh, closeBox })
</script>

<style scoped>
.verifybox {
  position: relative;
  box-sizing: border-box;
  border-radius: 2px;
  border: 1px solid #e4e7eb;
  background-color: #fff;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
.verifybox-top {
  padding: 0 15px;
  height: 50px;
  line-height: 50px;
  text-align: left;
  font-size: 16px;
  color: #45494c;
  border-bottom: 1px solid #e4e7eb;
  box-sizing: border-box;
}
.verifybox-bottom {
  padding: 15px;
  box-sizing: border-box;
}
.verifybox-close {
  position: absolute;
  top: 13px;
  right: 9px;
  width: 24px;
  height: 24px;
  text-align: center;
  cursor: pointer;
}
.mask {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1001;
  width: 100%;
  height: 100vh;
  background: rgba(0, 0, 0, 0.3);
  transition: all 0.5s;
}
.verify-tips {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 30px;
  line-height: 30px;
  color: #fff;
}
.suc-bg {
  background-color: rgba(92, 184, 92, 0.5);
}
.err-bg {
  background-color: rgba(217, 83, 79, 0.5);
}
</style>
